package org.alis.smallcc.alis.tools.lock.semaphore;

import java.util.Arrays;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

import lombok.extern.slf4j.Slf4j;

/**
 * 信号量锁
 * 
 * @author: luochuan
 * @date: 2020年10月29日 下午4:34:24
 */
@Slf4j
public class ResourceLock {
	private final Semaphore semaphore;
	private Boolean[] resourceArray;
	private Lock lock;

	public ResourceLock() {
		// 控制10个资源，使用先进先出的公平模式的信号量，先来的先获取，先进来的先获取信号量
		this.semaphore = new Semaphore(10, true);
		// 存放资源占用的状态 初始化资源都能用
		this.resourceArray = IntStream.range(0, 9).mapToObj(index -> Boolean.TRUE).toArray(Boolean[]::new);
		// 初始化锁->公平锁
		this.lock = new ReentrantLock(true);
	}

	/**
	 * 占用资源
	 * 
	 * @param userId
	 */
	public  void useResource(int userId,SourceWrapper<? super Integer> wrapper) {

		try {
			semaphore.acquire();
			// 占到一个坑
			Integer id = getResourceId();
			if(id>=0) {
				log.info("用户:{} 正在使用资源，资源id:{}\n",userId,id);
				// do something，相当于于使用资源
				wrapper.exection(id);
				// 退出这个坑
				resourceArray[id] = Boolean.TRUE;
			}else {
				log.info("用户:{} 拿不到可用用的资源",userId);
			}
			
		} catch (InterruptedException e) {
			log.error("异常堆栈->", e);
			Thread.currentThread().interrupt();
		} finally {
			// 释放信号量，计数器加1
			semaphore.release();
		}
	}

	/**
	 * 找到可以用的资源
	 * @return
	 */
	private int getResourceId() {
		lock.lock();
		try {
			//虽然使用了锁控制同步，但由于只是简单的一个数组遍历，效率还是很高的，所以基本不影响性能。
			return Arrays.asList(resourceArray).indexOf(Boolean.FALSE);
		
		} catch (Exception e) {
			log.error("找的过程中异常",e);
		} finally {
			lock.unlock();
		}
		return -1;
	}
}
